#pragma once

#include <atlframe.h>
#include <atlcrack.h>
#include <atlmisc.h>
#include <atlscrl.h>
#include <atlctrls.h>
#include "Theme.h"

template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>
class ATL_NO_VTABLE CSkinnedButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits>
{
public:
  DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())

  CSkinnedButtonImpl()
    : m_bDown(false), m_bPressed(false), m_bEnabled(true), m_bScaleImages(false)
  {}
  CSkinnedButtonImpl(const CImage& img, const CImage& imgPressed)
    : m_bDown(false), m_bPressed(false), m_bEnabled(true), m_bScaleImages(false)
  { m_image = img; m_imagePressed = imgPressed; }

  bool IsPressed()
  {
    return m_bPressed || m_bDown;
  }

  void SetPressed(bool pressed = true)
  {
    m_bPressed = pressed;
    Invalidate();
  }

  void SetScale(bool scale = true)
  { m_bScaleImages = scale; }

// extra
  const CImage& GetBackground() const
  { return m_imageBg; }
  const CImage& GetImage() const
  { return m_image; }
  const CImage& GetImagePressed() const
  { return m_imagePressed; }

  void SetImages(const CImage& bg, const CImage& image, const CImage& imagePressed)
  { m_imageBg = bg; m_image = image; m_imagePressed = imagePressed; }

// Overrideables
	void DoPaint(CDCHandle dc)
  {
    bool bPressed = m_bPressed || m_bDown;

    CRect rect;
	  GetClientRect(&rect);

    m_imageBg.Draw(dc, rect);

    // image
    CImage& img = bPressed ? m_imagePressed : m_image;
    if (!m_bScaleImages && rect.Width() >= img.width && rect.Height() >= img.height)
    {
      rect.left += (rect.Width() - img.width) / 2;
      rect.right = rect.left + img.width;
      rect.top += (rect.Height() - img.height) / 2;
      rect.bottom = rect.top + img.height;
    }
    img.Draw(dc, rect);
  }

// Message map and handlers
	BEGIN_MSG_MAP(CSkinnedButtonImpl)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
    MESSAGE_HANDLER(WM_HDCPAINT, OnHdcPaint)

		MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
		MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
		MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
		MESSAGE_HANDLER(WM_ENABLE, OnEnable)
		MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
		MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
		MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
	END_MSG_MAP()

	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		ModifyStyle(0, BS_OWNERDRAW);
		return bHandled = FALSE;
	}  

	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		return bHandled = TRUE;   // no background needed
	}

	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		if(wParam != NULL)
		{
			DoPaint((HDC)wParam);
		}
		else
		{
			CPaintDC dc(m_hWnd);
			DoPaint(dc.m_hDC);
		}
    return 0;
  }

  LRESULT OnHdcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  {
	  this->DoPaint((HDC)wParam);
    return bHandled = TRUE;
  }

	LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
		if(::GetCapture() == m_hWnd)
		{
			m_bDown = true;
			Invalidate();
		}
		return lRet;
	}

	LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
		return lRet;
	}

	LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if (m_bDown)
		{
			m_bDown = false;
			Invalidate();
		}
		bHandled = FALSE;
		return 1;
	}

	LRESULT OnEnable(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		Invalidate();
    m_bEnabled = (wParam == TRUE);
		bHandled = FALSE;
		return 1;
	}

	LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
	{
		if(::GetCapture() == m_hWnd)
		{
			POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
			ClientToScreen(&ptCursor);
			RECT rect = { 0 };
			GetWindowRect(&rect);
			bool bPressed = (::PtInRect(&rect, ptCursor) == TRUE);
			if(m_bDown != bPressed)
			{
				m_bDown = bPressed;
				Invalidate();
			}
		}
		bHandled = FALSE;
		return 1;
	}

	LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(wParam == VK_SPACE && !m_bDown)
		{
			m_bDown = true;
			Invalidate();
		}
		bHandled = FALSE;
		return 1;
	}

	LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(wParam == VK_SPACE && m_bDown)
		{
			m_bDown = false;
			Invalidate();
		}
		bHandled = FALSE;
		return 1;
	}

protected:
  CImage m_imageBg;
  CImage m_image;
  CImage m_imagePressed;

  bool   m_bDown;
  bool   m_bPressed;
  bool   m_bEnabled;
  bool   m_bScaleImages;
};

class CSkinnedButton : public CSkinnedButtonImpl<CSkinnedButton>
{
public:
	DECLARE_WND_SUPERCLASS(_T("_SkinnedButton"), GetWndClassName())

	CSkinnedButton() : 
		CSkinnedButtonImpl<CSkinnedButton>()
	{ }
};